// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package traffic

import (
	"apiote.xyz/p/szczanieckiej/config"

	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/text/transform"
)

type CalgaryTransit struct {
	client http.Client
}

func (CalgaryTransit) getTimezone() *time.Location {
	l, _ := time.LoadLocation("America/Edmonton")
	return l
}

func (g CalgaryTransit) ConvertVehicles() ([]Vehicle, error) {
	return []Vehicle{}, nil
}

func (z CalgaryTransit) GetVersions(_ time.Time, timezone *time.Location) ([]Version, error) {
	return []Version{{
		Link:      "https://data.calgary.ca/download/npk7-z3bj/application%2Fx-zip-compressed",
		ValidFrom: time.Date(0, time.January, 1, 0, 0, 0, 0, timezone),
		ValidTill: time.Date(9999, time.December, 31, 23, 59, 59, 999_999_999, timezone),
	}}, nil
}

func (CalgaryTransit) String() string {
	return "calgary_transit"
}

func (CalgaryTransit) RealtimeFeeds() map[RealtimeFeedType]string {
	return map[RealtimeFeedType]string{
		TRIP_UPDATES:      "https://data.calgary.ca/download/gs4m-mdc2/application%2Foctet-stream",
		VEHICLE_POSITIONS: "https://data.calgary.ca/download/am7c-qe3u/application%2Foctet-stream",
		ALERTS:            "https://data.calgary.ca/download/jhgn-ynqj/application%2Foctet-stream",
	}
}

func (CalgaryTransit) LuaUpdatesScript(config.Auth) string {
	return ""
}

func (CalgaryTransit) Transformer() transform.Transformer {
	return transform.Nop
}

func (CalgaryTransit) Name() string {
	return "Calgary Transit"
}

func (CalgaryTransit) Flags() FeedFlags {
	return FeedFlags{
		Headsign:     HeadsignTripHeadsing,
		StopIdFormat: "{{stop_code}}",
		StopName:     "{{stop_name}} [{{stop_code}}]",
		LineName:     "{{route_short_name}}",
	}
}

/*
TODO(11)
Correct all errors in GTFS file.
Everything that is not correct acording to the GTFS documentation is considered an error.
This function has access to unzipped GTFS file and can operate on files at `path/specific_file.txt`
*/
func (CalgaryTransit) FeedPrepareZip(path string) error {
	// route_id as in GTFS-RT AND names for CTrain and Max
	routesFile, err := os.Open(filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while opening routes file: %w", err)
	}
	defer routesFile.Close()
	routes2File, err := os.OpenFile(filepath.Join(path, "routes2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening routes2 file: %w", err)
	}
	defer routes2File.Close()
	r := csv.NewReader(bufio.NewReader(routesFile))
	w := csv.NewWriter(routes2File)
	header, err := r.Read()
	if err != nil {
		return fmt.Errorf("while reading routes header: %w", err)
	}
	fields := map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing routes header: %w", err)
	}

	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a route record: %w", err)
		}

		// record[fields["route_id"]] = strings.ReplaceAll(record[fields["route_id"]], "-20731", "")
		// switch record[fields["route_id"]] {
		// case "201-20728":
		// 	record[fields["route_short_name"]] = "CTrain Red"
		// case "202-20728":
		// 	record[fields["route_short_name"]] = "CTrain Blue"
		// }

		record[fields["route_id"]] = strings.Split(record[fields["route_id"]], "-")[0]
		switch record[fields["route_id"]] {
		case "201":
			record[fields["route_short_name"]] = "CTrain Red"
		case "202":
			record[fields["route_short_name"]] = "CTrain Blue"
		case "303":
			record[fields["route_short_name"]] = "MAX Orange"
		case "304":
			record[fields["route_short_name"]] = "MAX Yellow"
		case "306":
			record[fields["route_short_name"]] = "MAX Teal"
		case "307":
			record[fields["route_short_name"]] = "MAX Purple"
		}

		err = w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing a route record: %w", err)
		}
	}
	w.Flush()
	err = w.Error()
	if err != nil {
		return fmt.Errorf("while flushing routes: %w", err)
	}

	err = os.Remove(filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while removing routes: %w", err)
	}
	err = os.Rename(filepath.Join(path, "routes2.txt"), filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while renaming routes: %w", err)
	}

	tripsFile, err := os.Open(filepath.Join(path, "trips.txt"))
	if err != nil {
		return fmt.Errorf("while opening trips file: %w", err)
	}
	defer tripsFile.Close()
	trips2File, err := os.OpenFile(filepath.Join(path, "trips2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening trips2 file: %w", err)
	}
	defer trips2File.Close()
	r = csv.NewReader(bufio.NewReader(tripsFile))
	w = csv.NewWriter(trips2File)
	header, err = r.Read()
	if err != nil {
		return fmt.Errorf("while reading trips header: %w", err)
	}
	fields = map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing trips header: %w", err)
	}

	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a trip record: %w", err)
		}
		record[fields["route_id"]] = strings.Split(record[fields["route_id"]], "-")[0]
		// record[fields["route_id"]] = strings.ReplaceAll(record[fields["route_id"]], "-20731", "")
		err = w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing a trip record: %w", err)
		}
	}
	w.Flush()
	err = w.Error()
	if err != nil {
		return fmt.Errorf("while flushing trips: %w", err)
	}

	err = os.Remove(filepath.Join(path, "trips.txt"))
	if err != nil {
		return fmt.Errorf("while removing trips: %w", err)
	}
	err = os.Rename(filepath.Join(path, "trips2.txt"), filepath.Join(path, "trips.txt"))
	if err != nil {
		return fmt.Errorf("while renaming trips: %w", err)
	}
	return nil
}

func (CalgaryTransit) QRInfo() (string, QRLocation, string) {
	return "", QRLocationNone, ""
}
